Skip to content

[pull] main from MetaMask:main#734

Merged
pull[bot] merged 9 commits intoReality2byte:mainfrom
MetaMask:main
May 6, 2026
Merged

[pull] main from MetaMask:main#734
pull[bot] merged 9 commits intoReality2byte:mainfrom
MetaMask:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented May 6, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

chrisleewilcox and others added 9 commits May 6, 2026 07:17
…86) (#29754)

## **Description**

Empties `ALLOWLISTED_URLS` in `tests/api-mocking/mock-e2e-allowlist.ts`
by mocking the last remaining entry — the test-dapp's hardcoded
`metamask-fox.svg` URL.

After
[MMQA-1785](https://consensyssoftware.atlassian.net/browse/MMQA-1785),
`ALLOWLISTED_URLS` was down to one URL. This PR drops it to zero by
adding a default static-assets mock and deleting the entry. Cosmetic
milestone for parent epic
[MMQA-1364](https://consensyssoftware.atlassian.net/browse/MMQA-1364)
(epic AC: *"`ALLOWLISTED_URLS` is empty"*).

**Context — why no runtime change:**

- `metamask.github.io` is still in `ALLOWLISTED_HOSTS` (driven
separately by
[MMQA-1367](https://consensyssoftware.atlassian.net/browse/MMQA-1367)).
Hosts are matched first in `MockServerE2E.ts`, so the URL entry was
redundant in practice.
- The local DappServer serves `node_modules/@metamask/test-dapp/dist/`,
which contains a local `metamask-fox.svg`. The HTML references it
relatively (`<img src="metamask-fox.svg">`), so normal test-dapp loads
never hit GitHub.
- The hardcoded `https://metamask.github.io/test-dapp/metamask-fox.svg`
only appears inside the test-dapp's `wallet_watchAsset` button (sample
token image). Specs that exercise "Add Token" trigger that fetch — the
new mock now intercepts it with a minimal SVG response.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

[MMQA-1786](https://consensyssoftware.atlassian.net/browse/MMQA-1786)
Parent epic:
[MMQA-1364](https://consensyssoftware.atlassian.net/browse/MMQA-1364)

Fixes:

## **Manual testing steps**

```gherkin
Feature: Empty ALLOWLISTED_URLS via test-dapp fox SVG mock

  Scenario: ALLOWLISTED_URLS is empty after this change
    Given the e2e test infrastructure is running

    When MockServerE2E starts up
    Then ALLOWLISTED_URLS in mock-e2e-allowlist.ts contains zero entries

  Scenario: test-dapp wallet_watchAsset flow uses mocked SVG
    Given a spec exercises the Add Token button on the test-dapp

    When the test-dapp performs wallet_watchAsset with the metamask-fox.svg image URL
    Then the request to https://metamask.github.io/test-dapp/metamask-fox.svg is answered by the static-assets default mock with a minimal SVG
    And no live request leaks per validateLiveRequests()
```

## **Screenshots/Recordings**

### **Before**

`tests/api-mocking/mock-e2e-allowlist.ts`:

```ts
export const ALLOWLISTED_URLS = [
  // Temporarily allow existing live requests during migration
  'https://metamask.github.io/test-dapp/metamask-fox.svg',
];
```

### **After**

`tests/api-mocking/mock-e2e-allowlist.ts`:

```ts
export const ALLOWLISTED_URLS: string[] = [];
```

`tests/api-mocking/mock-responses/defaults/static-assets.ts` — new GET
matcher serving `MINIMAL_SVG`:

```ts
{
  urlEndpoint:
    /^https:\/\/metamask\.github\.io\/test-dapp\/metamask-fox\.svg$/,
  responseCode: 200,
  response: MINIMAL_SVG,
},
```

CI verification will be added once smoke tests complete on this PR.

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


[MMQA-1785]:
https://consensyssoftware.atlassian.net/browse/MMQA-1785?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
[MMQA-1364]:
https://consensyssoftware.atlassian.net/browse/MMQA-1364?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
[MMQA-1367]:
https://consensyssoftware.atlassian.net/browse/MMQA-1367?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
[MMQA-1786]:
https://consensyssoftware.atlassian.net/browse/MMQA-1786?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: only affects e2e API-mocking configuration by replacing a
previously allowlisted live URL with a deterministic mock response.
> 
> **Overview**
> Removes the last entry from `ALLOWLISTED_URLS` in e2e mocking so *no
full URLs are explicitly allowed* to hit live servers.
> 
> Adds a static-assets default GET mock for
`https://metamask.github.io/test-dapp/metamask-fox.svg`, returning
`MINIMAL_SVG`, so tests that fetch the test-dapp’s token image are
handled entirely by the mock server.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
f5bb7bc. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## **Description**

Removes all four Tenderly host entries from `ALLOWLISTED_HOSTS` in
`tests/api-mocking/mock-e2e-allowlist.ts`. Parent epic
[MMQA-1364](https://consensyssoftware.atlassian.net/browse/MMQA-1364).

The parent epic carved Tenderly out of scope on the assumption that
fork-based tests required live Tenderly virtual networks for contract
simulation. Re-investigation showed that assumption no longer holds.

**Disposition per host:**

| Entry | Disposition |
| --- | --- |
| `api.tenderly.co` | Delete — zero references in tests/app code |
| `rpc.tenderly.co` | Delete — zero references in tests/app code |
| `virtual.linea.rpc.tenderly.co` | Delete — already mocked by
`cardholder-mocks.ts:247-268` for the only specs that exercise it
(`card-home-add-funds.spec.ts`, `card-button.spec.ts`) |
| `virtual.mainnet.rpc.tenderly.co` | Default RPC mock added with regex
matcher (URL has UUID path); returns `0x0` to standard JSON-RPC methods,
mirroring the avax / zksync entries from
[MMQA-1785](https://consensyssoftware.atlassian.net/browse/MMQA-1785) |

**Bonus cleanup:** `tests/helpers/tenderly/tenderly.js` is deleted. Its
only function (`Tenderly.addFunds()` calling `tenderly_setBalance`) was
never called from anywhere in the codebase — that helper was the
original reason for the Tenderly carve-out, and it's dead code.

The Detox blacklist entry `.*rpc.tenderly.co/.*` in `blacklistURLs.json`
is also dropped — those URLs are now intercepted by the mock server.

After this lands, `ALLOWLISTED_HOSTS` is down to **7** entries (4 local
+ Polymarket carve-out + `metamask.github.io`).

## **Changelog**

CHANGELOG entry: null

## **Related issues**

[MMQA-1787](https://consensyssoftware.atlassian.net/browse/MMQA-1787)
Parent epic:
[MMQA-1364](https://consensyssoftware.atlassian.net/browse/MMQA-1364)

Fixes:

## **Manual testing steps**

```gherkin
Feature: E2E mock coverage for Tenderly virtual networks

  Scenario: on-ramp specs that load Tenderly Mainnet no longer leak live requests
    Given the on-ramp spec onramp-unified-buy.spec.ts is run
    And it builds a fixture with withNetworkController(CustomNetworks.Tenderly.Mainnet.providerConfig)

    When the wallet boots and the NetworkController initializes
    Then requests to virtual.mainnet.rpc.tenderly.co are answered by the default RPC mock
    And no entry for that host is required in mock-e2e-allowlist.ts

  Scenario: card specs continue to pass with Tenderly Linea host removed from allowlist
    Given the card spec card-home-add-funds.spec.ts is run

    When the wallet wires Tenderly.Linea and the test exercises the card flow
    Then RPC calls to virtual.linea.rpc.tenderly.co are intercepted by cardholder-mocks.ts
    And the spec passes without a live request leak

  Scenario: removed Tenderly helper does not break compilation
    Given tests/helpers/tenderly/tenderly.js has been deleted

    When the test suite is type-checked and built
    Then there are no broken import references
```

## **Screenshots/Recordings**

### **Before**

`tests/api-mocking/mock-e2e-allowlist.ts`:

```ts
export const ALLOWLISTED_HOSTS = [
  '0.0.0.0',
  '127.0.0.1',
  'localhost',
  '10.0.2.2',
  'api.tenderly.co',
  'rpc.tenderly.co',
  'virtual.mainnet.rpc.tenderly.co',
  'virtual.linea.rpc.tenderly.co',
  'gamma-api.polymarket.com',
  '*.polymarket.com',
  'metamask.github.io',
];
```

`tests/resources/blacklistURLs.json` — Detox dropping the host at the
network layer:

```
".*rpc.tenderly.co/.*"
```

`tests/helpers/tenderly/tenderly.js` — dead helper class with
`Tenderly.addFunds()`.

### **After**

`tests/api-mocking/mock-e2e-allowlist.ts` — four hosts removed:

```ts
export const ALLOWLISTED_HOSTS = [
  '0.0.0.0',
  '127.0.0.1',
  'localhost',
  '10.0.2.2',
  'gamma-api.polymarket.com',
  '*.polymarket.com',
  'metamask.github.io',
];
```

`tests/api-mocking/mock-responses/defaults/rpc-endpoints.ts` — new entry
for Tenderly mainnet:

```ts
{
  urlEndpoint: /^https:\/\/virtual\.mainnet\.rpc\.tenderly\.co\/.+$/,
  responseCode: 200,
  response: { jsonrpc: '2.0', id: 1, result: '0x0' },
},
```

`tests/resources/blacklistURLs.json` — Tenderly entry removed.

`tests/helpers/tenderly/tenderly.js` — file deleted.

CI verification will be added once smoke tests complete on this PR.

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


[MMQA-1364]:
https://consensyssoftware.atlassian.net/browse/MMQA-1364?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
[MMQA-1785]:
https://consensyssoftware.atlassian.net/browse/MMQA-1785?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk test-infrastructure change that tightens E2E network mocking;
main risk is unintended interception/mismatch of Tenderly RPC URLs
causing E2E failures.
> 
> **Overview**
> Removes all Tenderly domains from the E2E `ALLOWLISTED_HOSTS`,
reducing live-network carve-outs.
> 
> Adds a default RPC mock for `virtual.mainnet.rpc.tenderly.co` using a
regex URL matcher, deletes the unused
`tests/helpers/tenderly/tenderly.js` helper, and drops the Detox
`.*rpc.tenderly.co/.*` blacklist entry so these requests are handled by
the mock server instead.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
485d840. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
<!--
Please submit this PR as a draft initially.
Do not mark it as "Ready for review" until the template has been
completely filled out, and PR status checks have passed at least once.
-->

## **Description**

This change aligns MetaMask Mobile’s Send flow with the extension by
surfacing **first-time recipient interaction** and **token contract**
warnings before the user continues to confirmation.

**Reason:** Users should be explicitly warned when sending to an address
they have not interacted with on-chain before, and when the recipient
looks like a token contract, so they can double-check the destination.

**Solution:**

- Added `checkFirstTimeInteraction` in
`app/util/transaction-controller/index.ts`, using
`getAccountAddressRelationship` from the transaction-controller preview
package so semantics match the extension.
- Introduced send-flow alert hooks (`useFirstTimeInteractionSendAlert`,
`useTokenContractSendAlert`) and an aggregator `useSendAlerts` that
orders alerts (token contract first, then first-time interaction).
- Refactored `SendAlertModal` to accept multiple `SendAlert` items with
prev/next navigation (design-system `ButtonIcon`, no “N of M” counter)
and per-step acknowledge labels where needed.
- Updated `Recipient` to open the modal when there are unacknowledged
alerts, reset acknowledgement when the recipient changes, and block
Review / auto-advance while alert checks are pending.
- Removed the old `toAddressErrorAllowAcknowledge` path from address
validation in favor of the dedicated alert pipeline; token-contract
detection moved out of `validateHexAddress` into the alert hook.
- Added/updated unit tests and locale strings for the new copy and
navigation accessibility labels.

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: Added Send flow warnings for first-time recipient
interaction

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1016

## **Manual testing steps**

```gherkin
Feature: Send flow first-time recipient

  Background:
    Given I am logged into MetaMask Mobile
    And I am on the Send flow recipient step for an EVM network

  Scenario: user sees first-time interaction alert for a new recipient
    Given I have an externally owned recipient address I have never sent to on this network
    And the recipient is not one of my accounts and is not shown as verified while trust data loads

    When user enters or selects that recipient and taps Review (or equivalent continue)
    Then a warning modal should appear about sending to this address for the first time
    And the modal should show the recipient address in the message

    When user acknowledges the alert (e.g. Continue / I understand as labeled)
    Then the flow should proceed toward confirmation as usual
```

## **Screenshots/Recordings**



https://github.com/user-attachments/assets/920408e5-a5b1-484c-9b1d-162bd170a666



<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes the Send recipient step gating logic and adds new asynchronous
alert checks (token contract lookup and first-time interaction API),
which can affect when users can proceed and may introduce edge cases
around pending/acknowledgement state.
> 
> **Overview**
> Adds a new Send-flow alert pipeline (`useSendAlerts`) that surfaces
**token contract** and **first-time recipient interaction** warnings
before proceeding to confirmation, backed by a new
`checkFirstTimeInteraction` util that calls
`getAccountAddressRelationship`.
> 
> Refactors `SendAlertModal` to accept a list of `SendAlert`s with
prev/next navigation and per-alert acknowledge labels, and updates
`Recipient` to block Review/auto-advance while alert checks are pending
and to require acknowledging any unacknowledged alerts.
> 
> Removes the old `toAddressErrorAllowAcknowledge`/token-contract
detection from address validation
(`validateHexAddress`/`useToAddressValidation`) and updates
tests/locales accordingly.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
45a6f81. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Update font for token details label.

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry: Update font for token details label


## **Related issues**

Fixes: null

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI-only typography change that does not affect navigation,
data, or analytics behavior.
> 
> **Overview**
> Updates the `SecurityTrustEntryCard` result label styling by switching
from `TextVariant.HeadingMd` with a hard-coded `600` weight to
`TextVariant.BodyMd` with `FontWeight.Medium`, aligning the label’s
typography with the design system.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
827c6b1. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
…29774)

<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

Update package @metamask/transaction-pay-controller.

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry:

## **Related issues**

Fixes: https://consensyssoftware.atlassian.net/browse/CONF-1241

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**
NA

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [X] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [X] I've completed the PR template to the best of my ability
- [X] I've included tests if applicable
- [X] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [X] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Upgrades the `@metamask/transaction-pay-controller` and related
controller dependencies, which could subtly affect transaction/payment
flows even though this PR mostly updates dependency metadata and test
fixtures.
> 
> **Overview**
> Updates `@metamask/transaction-pay-controller` from `^20.0.0` to
`^21.0.0`, pulling in newer versions of several MetaMask controller
packages via `yarn.lock`.
> 
> Adjusts test fixtures to match the new dependency behavior:
`initial-background-state.json` now seeds `AssetsController.assetsInfo`
with `mUSD` token metadata on multiple chains, and E2E RPC mocking adds
a default mock for `https://testnet-rpc.monad.xyz/`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
c20bef9. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Adds Perps Trading campaign outcome support to the Rewards stack,
mirroring the Ondo GM outcome pattern.

After a Perps Trading campaign ends, opted-in participants can query
`GET /perps-trading/:campaignId/outcome/me` to learn whether they won.
This PR wires that endpoint into the mobile app end-to-end:

- **Winners** (have a `winnerVerificationCode` + `pending` status) see a
toast → tap → `PerpsTradingCampaignWinningView` showing their rank,
verification code (copy or email to claim prize)
- **Non-winners once results are final** (`finalized` status, no code)
see a toast → tap → campaigns view

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: rwds-perps-trading-outcome

## **Changes**

| Layer | File | What |
|---|---|---|
| Types | `types.ts` | `CampaignType.PERPS_TRADING`,
`PerpsTradingCampaignParticipantOutcomeDto` |
| Data service | `rewards-data-service.ts` |
`getPerpsTradingCampaignParticipantOutcome()` → `GET
/perps-trading/:campaignId/outcome/me` |
| Controller | `RewardsController.ts` | Method with 10-min in-memory
cache + auth retry |
| Action types / Messenger | multiple | Registered in action union and
allowed actions |
| Hook | `usePerpsTradingCampaignParticipantOutcome.ts` | Fetches
outcome via controller messenger |
| Toast hook | `usePerpsTradingCampaignEndedOutcomeToast.ts` |
`winner_pending` → winning view; `participant_finalized` → campaigns |
| Screen | `PerpsTradingCampaignWinningView.tsx` | Rank + verification
code, copy + mailto |
| Utility | `formatUtils.ts` | `formatOrdinalRank()` (1st/2nd/3rd…) |
| Routes / Navigator | multiple | New route constant, screen registered,
toast hook wired |
| Strings | `en.json` | Toast + winning view copy |

## **Manual testing steps**

```gherkin
Feature: Perps Trading campaign outcome

  Scenario: winner sees outcome toast and winning view
    Given a Perps Trading campaign that has ended
    And the current user is opted in and has a winner row with status "pending" and a verification code

    When the user opens the Rewards section
    Then a toast appears: "You won! 🏆" with "View details" link
    When the user taps "View details"
    Then the PerpsTradingCampaignWinningView opens showing their rank and verification code
    And the user can copy the code or tap "Open mail" to email perpscampaign@consensys.net

  Scenario: non-winner sees finalized toast
    Given a Perps Trading campaign that has ended with 20 finalized winners
    And the current user is opted in but has no winner row

    When the user opens the Rewards section
    Then a toast appears: "The results are in" with "View" link
    When the user taps "View"
    Then the user is navigated to the campaigns view
```

## **Screenshots/Recordings**

### **Before**

No Perps Trading outcome UI.

### **After**
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-05-05 at 19 33 02"
src="https://github.com/user-attachments/assets/c2d21dda-6db6-4260-b0b3-480cbea38f18"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-05-05 at 20 50 09"
src="https://github.com/user-attachments/assets/aae8fafb-2bac-4349-83d7-ba00182fa498"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-05-05 at 20 53 05"
src="https://github.com/user-attachments/assets/425fc361-d51f-4d54-a8e6-39f3b34fe1c3"
/>
<img width="1179" height="2556" alt="Simulator Screenshot - E2E Test -
2026-05-05 at 20 53 10"
src="https://github.com/user-attachments/assets/c96b8fb0-c19d-4b85-a1a4-81af881aa612"
/>


_(to be added — requires a completed Perps Trading campaign with backend
data)_

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [x] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds new post-campaign outcome UI/UX (toasts, auto-navigation, new
routes/screens) that can affect user navigation and state gating across
Rewards; issues would mainly surface as incorrect redirects or missing
banners/toasts.
> 
> **Overview**
> Adds a shared `CampaignWinningView` and wires both Ondo and Perps
campaigns to use it for winner verification-code display (copy + mailto)
with a consistent fallback when no code is available.
> 
> Introduces a generic `useCampaignParticipantOutcome` +
`useCampaignOutcomeToast` pattern, then adds Perps Trading support via
`usePerpsTradingCampaignParticipantOutcome` and
`usePerpsTradingCampaignEndedOutcomeToast`, mounting these toasts on
`RewardsDashboard` and `CampaignsView`.
> 
> Expands Perps Trading end-of-campaign UX: new
`PerpsTradingCampaignWinningView` route/screen, outcome banners on
details/stats (with one-time session auto-navigation for pending
winners), an ended-campaign stats panel, and tweaks to
completed-campaign stat presentation (hide pending tag; hide
volume/margin once complete). Also consolidates outcome banner locale
keys and generalizes `CampaignOutcomeBanner` usage across campaigns.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
464bd29. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: sophieqgu <sophieqgu@gmail.com>
<!--
Please submit this PR as a draft initially.

Do not mark it as "Ready for review" until this PR meets the canonical
Definition of Ready For Review in `docs/readme/ready-for-review.md`.

In short: the template must be materially complete (not just section
titles
present), all status checks must be currently passing, and the only
expected
follow-up commits must be reviewer-driven.
-->

## **Description**

<!--
Write a short description of the changes included in this pull request,
also include relevant motivation and context. Have in mind the following
questions:
1. What is the reason for the change?
2. What is the improvement/solution?
-->

## **Changelog**

<!--
If this PR is not End-User-Facing and should not show up in the
CHANGELOG, you can choose to either:
1. Write `CHANGELOG entry: null`
2. Label with `no-changelog`

If this PR is End-User-Facing, please write a short User-Facing
description in the past tense like:
`CHANGELOG entry: Added a new tab for users to see their NFTs`
`CHANGELOG entry: Fixed a bug that was causing some NFTs to flicker`

(This helps the Release Engineer do their job more quickly and
accurately)
-->

CHANGELOG entry:

## **Related issues**

Fixes:

## **Manual testing steps**

```gherkin
Feature: my feature name

  Scenario: user [verb for user action]
    Given [describe expected initial app state]

    When user [verb for user action]
    Then [describe expected outcome]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

<!--
Every checklist item must be consciously assessed before marking this PR
as
"Ready for review". A checked box means you deliberately considered that
responsibility, not that you literally performed every action listed.

Unchecked boxes are ambiguous: they are not an implicit "N/A" and they
are not
a silent "skip". See `docs/readme/ready-for-review.md` for the full
checklist
semantics.
-->

- [ ] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [ ] I've completed the PR template to the best of my ability
- [ ] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
  - Ideally on a mid-range device; emulator is acceptable
- [ ] I've tested with a power user scenario
- Use these [power-user
SRPs](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/edit-v2/401401446401?draftShareId=9d77e1e1-4bdc-4be1-9ebb-ccd916988d93)
to import wallets with many accounts and tokens
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics
- See [`trace()`](/app/util/trace.ts) for usage and
[`addToken`](/app/components/Views/AddAsset/components/AddCustomToken/AddCustomToken.tsx#L274)
for an example

For performance guidelines and tooling, see the [Performance
Guide](https://consensyssoftware.atlassian.net/wiki/spaces/TL1/pages/400085549067/Performance+Guide+for+Engineers).

## **Pre-merge reviewer checklist**

<!--
Reviewer checklist items follow the same semantics as the author
checklist: an
unchecked box is ambiguous, a checked box means the reviewer consciously
assessed that responsibility. See `docs/readme/ready-for-review.md`.
-->

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk: changes are confined to Playwright test
tagging/configuration and documentation, primarily affecting which tests
are selected by `--grep` and CI scripts.
> 
> **Overview**
> Introduces **test-type tags** `@Performance` and `@System` (in
`tests/tags.performance.js`) and updates performance specs to include
these tags in `test.describe()` names so Playwright configs can filter
suites via `grep`.
> 
> Adds new `package.json` scripts to run **system tests on local Android
emulators and iOS simulators** using
`tests/playwright.system-emulator.config.ts`, and updates MM Connect and
other performance/system specs to be grouped under the new tagging
convention. Documentation in `tests/performance/README.md` is expanded
to explain the new tag types, conventions, and examples.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
28088c1. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

Seitrace (`https://seitrace.com`), the current Sei Mainnet block
explorer, is being decommissioned. This PR swaps every hardcoded
reference to `seiscan.io` and adds migration **134** to rewrite existing
users' persisted `NetworkController` state on upgrade.

Hardcoded URL swaps:

- `app/util/networks/customNetworks.tsx` — Sei Mainnet
`blockExplorerUrl`
- `tests/resources/networks.e2e.js` — e2e resource
- `tests/api-mocking/mock-responses/tx-sentinel-networks-map.ts` — mock
`explorer`

Migration 134 rewrites

`engine.backgroundState.NetworkController.networkConfigurationsByChainId['0x531'].blockExplorerUrls`
from `seitrace.com` to `seiscan.io` for existing installs. It only
touches entries still pointing at `seitrace.com` — a user who customized
their Sei block explorer (e.g. to `seistream.app`) is left alone. The
migration follows mobile's current pattern (sync arrow function with
in-place `state` mutation), and is registered in
`app/store/migrations/index.ts`. Cross-repo reference for this family
of block-explorer-URL migrations is

[`metamask-extension/app/scripts/migrations/197.ts`](https://github.com/MetaMask/metamask-extension/blob/main/app/scripts/migrations/197.ts).

The `@metamask/controller-utils` bump is deliberately deferred until
the sibling PR in `MetaMask/core` releases; this PR stands alone.

## **Changelog**

CHANGELOG entry: Fixed Sei Mainnet: replaced deprecated Seitrace
explorer with Seiscan (`https://seiscan.io`). Existing installs are
migrated via migration 134.

## **Related issues**

Fixes:

Companion PRs:
- [`MetaMask/core#8545`](MetaMask/core#8545) —
default `BlockExplorerUrl[SeiMainnet]`
-
[`MetaMask/metafi-sdk#525`](MetaMask/metafi-sdk#525)
— shared SDK `SEI_EXPLORER`
-
[`MetaMask/metamask-extension#42064`](MetaMask/metamask-extension#42064)
— extension migration 207

## **Manual testing steps**

```gherkin
Feature: Sei Mainnet block explorer URL

  Scenario: fresh install uses Seiscan
    Given a fresh install of MetaMask Mobile
    When the user adds the Sei Mainnet network
    Then the network's block-explorer URL is "https://seiscan.io/"
    And tapping a Sei transaction's "View on block explorer" opens "https://seiscan.io/tx/<hash>"

  Scenario: existing user with Seitrace URL is migrated
    Given a build prior to this change with Sei Mainnet added
    And the stored "blockExplorerUrls" is ["https://seitrace.com"]
    When the user upgrades to this build
    Then migration 134 runs
    And the stored "blockExplorerUrls" for Sei Mainnet is ["https://seiscan.io"]

  Scenario: user-customized URL is preserved
    Given a build prior to this change with Sei Mainnet added
    And the user has customized "blockExplorerUrls" to ["https://seistream.app"]
    When the user upgrades to this build
    Then migration 134 is a no-op for this entry
    And the stored "blockExplorerUrls" for Sei Mainnet remains ["https://seistream.app"]
```

## **Screenshots/Recordings**

<!-- If applicable, add screenshots and/or recordings to visualize the
before and after of your change. -->

### **Before**

<!-- [screenshots/recordings] -->

### **After**

<!-- [screenshots/recordings] -->

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [x] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
- [ ] I've tested with a power user scenario
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics

## **Pre-merge reviewer checklist**

- [ ] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [ ] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Adds a new persisted-state migration that mutates `NetworkController`
network configs for Sei Mainnet; while narrowly scoped, migrations run
on upgrade and can affect existing user state if bugs slip through.
> 
> **Overview**
> Updates Sei Mainnet’s default block explorer from **Seitrace** to
**Seiscan** across the in-app popular network config and test fixtures.
> 
> Adds migration `134` (registered in `app/store/migrations/index.ts`)
to rewrite persisted Sei Mainnet `blockExplorerUrls` entries whose URL
hostname is exactly `seitrace.com` to `seiscan.io`, while leaving
missing/invalid controller state and user-customized/lookalike URLs
untouched; includes unit tests covering the rewrite and no-op cases.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
68e91bc. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
## **Description**

The "Move mUSD" row in the Add money sheet was showing a balance that
did not match the Money Account balance displayed at the top of the
screen. The two figures were sourced from different places, which
surfaced as an obvious mismatch whenever the selected EVM account was
not the same as the Money Account.

Root cause: the sheet was reading from
`useMusdBalance().fiatBalanceAggregatedFormatted`, which aggregates mUSD
across the currently selected EVM account. The screen header, by
contrast, uses `useMoneyAccountBalance`, which is the canonical Money
Account balance.

Fix: switch the sheet to consume
`useMoneyAccountBalance().totalFiatFormatted` so the "Move mUSD" amount
and the header always agree. Tests were updated to mock the new hook and
assert the same fallback behaviour (no-amount copy when the balance is
unavailable, locale fiat prefix preserved).

Credit to Matthew Grainger for diagnosing the source-of-truth mismatch
on the Jira ticket.

## **Changelog**

CHANGELOG entry: null

## **Related issues**

Fixes: MUSD-701

## **Manual testing steps**

```gherkin
Feature: Add money sheet balance consistency

  Scenario: user opens the Add money sheet with a funded Money Account
    Given the user has a non-zero Money Account balance
    And the selected EVM account is not the Money Account
    When the user opens the Add money sheet
    Then the "Move mUSD" row shows the same fiat amount as the Money Account header

  Scenario: user opens the Add money sheet with no mUSD
    Given the user's Money Account balance is unavailable or zero
    When the user opens the Add money sheet
    Then the "Move mUSD" row shows the no-amount copy
```

## **Screenshots/Recordings**

### **Before**

### **After**

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs) and [MetaMask Mobile
Coding
Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md).
- [x] I've completed the PR template to the best of my ability
- [x] I've included tests if applicable
- [ ] I've documented my code using [JSDoc](https://jsdoc.app/) format
if applicable
- [ ] I've applied the right labels on the PR (see [labeling
guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)).
Not required for external contributors.

#### Performance checks (if applicable)

- [ ] I've tested on Android
- [ ] I've tested with a power user scenario
- [ ] I've instrumented key operations with Sentry traces for production
performance metrics

## **Pre-merge reviewer checklist**

- [x] I've manually tested the PR (e.g. pull and build branch, run the
app, test code being changed).
- [x] I confirm that this PR addresses all acceptance criteria described
in the ticket it closes and includes the necessary testing evidence such
as recordings and or screenshots.

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> Low risk UI data-source swap: the “Move mUSD” row now reads from the
canonical Money Account balance, which could only affect displayed copy
if the previous EVM-account-aggregated value differed or was undefined.
> 
> **Overview**
> Updates the Add Money bottom sheet so the “Move mUSD” option displays
the **Money Account** fiat balance (via
`useMoneyAccountBalance().totalFiatFormatted`) instead of the previously
EVM-account-aggregated `useMusdBalance()` value, eliminating mismatches
with the header balance.
> 
> Adjusts `MoneyAddMoneySheet` tests to mock the new hook and keep the
same behaviors for locale-prefixed amounts and the no-amount fallback
copy.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
88dd0bc. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@pull pull Bot locked and limited conversation to collaborators May 6, 2026
@pull pull Bot added the ⤵️ pull label May 6, 2026
@pull pull Bot merged commit 9432aa0 into Reality2byte:main May 6, 2026
4 of 16 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants